/*
 * Digital Audio Mobile - A multi track studio for Windows Mobile
 * Copyright (C) 2008 David Olsson
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <windows.h>
#include <mmsystem.h>

#include "DeviceFactory.h"
#include "InputDevice.h"
#include "OutputDevice.h"

using namespace std;

DeviceFactory::DeviceFactory() throw() {
    for(UINT i = 0; i < waveInGetNumDevs(); i++) {
        WAVEINCAPS caps;
        waveInGetDevCaps(i, &caps, sizeof(WAVEINCAPS));
        DeviceInfo info;
        info.index = i;
        info.format.cbSize = 0;
        info.format.wFormatTag = WAVE_FORMAT_PCM;
        if(caps.dwFormats & WAVE_FORMAT_1M08) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 11025;
            info.format.wBitsPerSample = 8;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 11025Hz, 8 bits)"));
            m_inputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_1M16) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 11025;
            info.format.wBitsPerSample = 16;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 11025Hz, 16 bits)"));
            m_inputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_2M08) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 22050;
            info.format.wBitsPerSample = 8;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 22050Hz, 8 bits)"));
            m_inputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_2M16) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 22050;
            info.format.wBitsPerSample = 16;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 22050Hz, 16 bits)"));
            m_inputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_4M08) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 44100;
            info.format.wBitsPerSample = 8;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 44100Hz, 8 bits)"));
            m_inputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_4M16) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 44100;
            info.format.wBitsPerSample = 16;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 44100Hz, 16 bits)"));
            m_inputDevices.push_back(info);
        }
    }

    for(UINT i = 0; i < waveOutGetNumDevs(); i++) {
        WAVEOUTCAPS caps;
        waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS));
        DeviceInfo info;
        info.index = i;
        info.format.cbSize = sizeof(WAVEFORMATEX);
        info.format.wFormatTag = WAVE_FORMAT_PCM;
        if(caps.dwFormats & WAVE_FORMAT_1M08) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 11025;
            info.format.wBitsPerSample = 8;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 11025Hz, 8 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_1M16) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 11025;
            info.format.wBitsPerSample = 16;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 11025Hz, 16 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_1S08 && caps.wChannels == 2) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 2;
            info.format.nSamplesPerSec = 11025;
            info.format.wBitsPerSample = 8;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(stereo, 11025Hz, 8 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_1S16 && caps.wChannels == 2) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 2;
            info.format.nSamplesPerSec = 11025;
            info.format.wBitsPerSample = 16;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(stereo, 11025Hz, 16 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_2M08) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 22050;
            info.format.wBitsPerSample = 8;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 22050Hz, 8 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_2M16) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 22050;
            info.format.wBitsPerSample = 16;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 22050Hz, 16 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_2S08 && caps.wChannels == 2) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 2;
            info.format.nSamplesPerSec = 22050;
            info.format.wBitsPerSample = 8;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(stereo, 22050Hz, 8 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_2S16 && caps.wChannels == 2) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 2;
            info.format.nSamplesPerSec = 22050;
            info.format.wBitsPerSample = 16;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(stereo, 22050Hz, 16 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_4M08) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 44100;
            info.format.wBitsPerSample = 8;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 44100Hz, 8 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_4M16) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 1;
            info.format.nSamplesPerSec = 44100;
            info.format.wBitsPerSample = 16;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(mono, 44100Hz, 16 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_4S08 && caps.wChannels == 2) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 2;
            info.format.nSamplesPerSec = 44100;
            info.format.wBitsPerSample = 8;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(stereo, 44100Hz, 8 bits)"));
            m_outputDevices.push_back(info);
        }
        if(caps.dwFormats & WAVE_FORMAT_4S16 && caps.wChannels == 2) {
            _tcscpy(info.devName, caps.szPname);
            _tcscat(info.devName, TEXT(" "));
            info.format.nChannels = 2;
            info.format.nSamplesPerSec = 44100;
            info.format.wBitsPerSample = 16;
            info.format.nBlockAlign = info.format.nChannels * (info.format.wBitsPerSample / 8);
            info.format.nAvgBytesPerSec = info.format.nSamplesPerSec * info.format.nBlockAlign;
            _tcscat(info.devName, TEXT("(stereo, 44100Hz, 16 bits)"));
            m_outputDevices.push_back(info);
        }
    }
}

unsigned int DeviceFactory::numInputDevices() const throw() {
    return(m_inputDevices.size());
}

const TCHAR *DeviceFactory::inputDeviceName(unsigned int index) const throw() {
    return(m_inputDevices[index].devName);
}

InputDevice *DeviceFactory::instantiateInputDevice(unsigned int index) throw() {
    return(new InputDevice(m_inputDevices[index].index, m_inputDevices[index].format));
}

unsigned int DeviceFactory::numOutputDevices() const throw() {
    return(m_outputDevices.size());
}

const TCHAR *DeviceFactory::outputDeviceName(unsigned int index) const throw() {
    return(m_outputDevices[index].devName);
}

OutputDevice *DeviceFactory::instantiateOutputDevice(unsigned int index) throw() {
    return(new OutputDevice(m_outputDevices[index].index, m_outputDevices[index].format));
}
